#ifndef BEZIER_HPP
#define BEZIER_HPP

#include <vector>
#include <utility>

/**
 * @class Bezier
 * @brief This class represents a cubic Bezier curve defined by four control points.
 *
 * The Bezier curve is parameterized by a value `t` in the range [0, 1]. It interpolates
 * between the four control points using cubic blending functions, making it useful for
 * generating smooth curves in computer graphics, animation, and design.
 */
class Bezier {
private:
    std::pair<double, double> q0; ///< The first control point of the curve
    std::pair<double, double> q1; ///< The second control point of the curve
    std::pair<double, double> q2; ///< The third control point of the curve
    std::pair<double, double> q3; ///< The fourth control point of the curve

public:
    /**
     * @brief Constructor to initialize a cubic Bezier curve with four control points.
     *
     * @param q0 The first control point, corresponding to t = 0.
     * @param q1 The second control point, affecting the initial shape of the curve.
     * @param q2 The third control point, affecting the end shape of the curve.
     * @param q3 The fourth control point, corresponding to t = 1.
     *
     * Each control point is a pair of doubles representing x and y coordinates.
     */
    Bezier(const std::pair<double, double>& q0, const std::pair<double, double>& q1,
           const std::pair<double, double>& q2, const std::pair<double, double>& q3)
        : q0(q0), q1(q1), q2(q2), q3(q3) {}

    /**
     * @brief Computes the point on the Bezier curve at a specified parameter `t`.
     *
     * @param t The parameter value, ranging from 0 to 1, where:
     *          - t = 0 returns the starting control point (q0).
     *          - t = 1 returns the ending control point (q3).
     *          - Intermediate values produce points along the curve.
     * @return The point on the curve as a `std::pair<double, double>`, representing
     *         the x and y coordinates of the computed point.
     *
     * This function uses the Bernstein polynomial form of the cubic Bezier curve:
     *   B(t) = (1 - t)^3 * q0 + 3 * (1 - t)^2 * t * q1 + 3 * (1 - t) * t^2 * q2 + t^3 * q3
     */
    std::pair<double, double> evaluate(double t) const {
        // Calculate the x-coordinate based on the Bernstein polynomial
        double x = (1.0 - t) * (1.0 - t) * (1.0 - t) * q0.first +
                    3.0 * (1.0 - t) * (1.0 - t) * t * q1.first +
                    3.0 * (1.0 - t) * t * t * q2.first +
                    t * t * t * q3.first;

        // Calculate the y-coordinate based on the Bernstein polynomial
        double y = (1.0 - t) * (1.0 - t) * (1.0 - t) * q0.second +
                    3.0 * (1.0 - t) * (1.0 - t) * t * q1.second +
                    3.0 * (1.0 - t) * t * t * q2.second +
                    t * t * t * q3.second;

        // Return the computed point on the curve
        return std::make_pair(x, y);
    }
};

#endif // BEZIER_HPP